home *** CD-ROM | disk | FTP | other *** search
- /* :ts=8 bk=0
- *
- * tree.c: Demonstrater for the hypothetical HTXT form. A simple
- * hypertext like structure to demo the more complex
- * possibilities for parsing.
- * Alpha Concept Prototype.
- *
- * Usage: tree -i/o/r <file>
- *
- * Writes and parses HTXT trees between memory and file. The in-memory
- * structure gets written to the file and the file gets read directly
- * into the same structure using custom handlers.
- *
- * -i reads the file using custom handlers.
- * -r reads the file using a recursive-descent parser.
- * -o writes the demo file.
- *
- * Stuart Ferguson 8810.18
- * ewhac: adjusted a tiny bit 8811.02
- * shf: adjusted for Dec 88 revision 8812.18
- * ewhac: Updated to 1.4 Beta 8912.06
- * ewhac: Latticeification 9005.31
- */
-
- #include <exec/types.h>
- #include <libraries/dos.h>
- #include <utility/hooks.h>
- #include <libraries/iffparse.h>
- #include <clib/exec_protos.h>
- #include <clib/dos_protos.h>
- #include "iffparse_protos.h"
- #include "iffparse.p"
-
- #define ID_HTXT MAKE_ID('H','T','X','T')
- #define ID_CHRS MAKE_ID('C','H','R','S')
-
- /*
- * Forward function declarations. (I hate ANSI.)
- */
- LONG WriteTree (struct IFFHandle *, struct HNode *);
- LONG ReadTree (struct IFFHandle *);
- LONG ReadTreeR (struct IFFHandle *);
- LONG __saveds __asm TreeHandler (register __a0 struct Hook *, register __a2 struct IFFHandle *, register __a1 LONG *);
- LONG __saveds __asm TextHandler (register __a0 struct Hook *, register __a2 struct IFFHandle *, register __a1 LONG *);
- LONG __saveds __asm PurgeVHNode (register __a0 struct Hook *, register __a2 struct LocalContextItem *, register __a1 LONG *);
- struct HNode *ReadTreeForm (struct IFFHandle *);
- char *ReadTextChunk (struct IFFHandle *);
- void AddEnd (struct vHNode *, struct HNode *);
- void PrintTree (struct HNode *, int);
- void FreeTree (struct HNode *);
-
-
- /*
- * Tree data structure consists of these types of nodes strung out
- * into trees. Type is either HN_NODE or HN_LEAF.
- */
- struct HNode {
- struct HNode *next;
- void *val;
- long type;
- };
-
- #define HN_NODE 0
- #define HN_LEAF 1
-
- /*
- * vHNode's will hold temporary parse states in the local context.
- */
- struct vHNode {
- struct HNode *val;
- };
- #define LCI_HNODE MAKE_ID('h','n','o','d')
-
- /*
- * Demo text tree structure for output.
- */
- struct HNode dtree[] = {
- { NULL, &dtree[1], HN_NODE },
- { &dtree[2], "This is the text body.", HN_LEAF },
- { &dtree[5], &dtree[3], HN_NODE },
- { &dtree[4], "More stuff.", HN_LEAF },
- { NULL, "Even more stuff.", HN_LEAF },
- { NULL, &dtree[6], HN_NODE },
- { NULL, "Nested text ...", HN_LEAF }
- };
-
-
- /*
- * Buffer for text from IFF file. Could do this dynamically, but
- * this makes things easier for this simple case.
- */
- char tbuf[500];
- int bufpos = 0;
-
- struct Library *IFFParseBase;
-
-
- main (argc, argv)
- int argc;
- char **argv;
- {
- struct IFFHandle *iff = NULL;
- long error;
- long filemode;
- int recur;
-
- if (argc != 3) {
- printf ("usage: %s -i/o/r <file>\n", argv[0]);
- goto die;
- }
-
- if (!(IFFParseBase = OpenLibrary ("iffparse.library", 0L))) {
- puts ("Cannot open library.");
- goto die;
- }
-
- /*
- * Get file i/o direction - 'o' = NEWFILE, 'i/r' = OLDFILE
- */
- filemode = MODE_OLDFILE;
- if (argv[1][1] == 'o')
- filemode = MODE_NEWFILE;
-
- recur = (argv[1][1] == 'r');
-
- /*
- * Standard IFF open sequence:
- * AllocIFF()
- * assign stream pointer and setup stream handler vectors
- * OpenIFF()
- */
- if (!(iff = AllocIFF())) {
- puts ("AllocIFF() failed.");
- goto die;
- }
-
- if (!(iff -> iff_Stream = Open (argv[2], filemode))) {
- puts ("File open failed.");
- goto die;
- }
- InitIFFasDOS (iff);
-
- if (error = OpenIFF
- (iff, filemode==MODE_OLDFILE ? IFFF_READ : IFFF_WRITE))
- {
- puts ("OpenIFF failed.");
- goto die;
- }
-
- if (filemode == MODE_NEWFILE) {
- puts ("writing tree structure...");
- PrintTree (dtree, 1);
- error = WriteTree (iff, dtree);
- } else if (recur)
- error = ReadTreeR (iff);
- else
- error = ReadTree (iff);
-
- if (error)
- printf ("Operation aborted (%ld)\n", error);
-
- die:
- /*
- * Standard close sequence (reverse of open):
- * CloseIFF()
- * close stream
- * FreeIFF()
- */
- if (iff) {
- CloseIFF (iff);
- if (iff -> iff_Stream)
- Close (iff -> iff_Stream);
- FreeIFF (iff);
- }
- if (IFFParseBase) CloseLibrary (IFFParseBase);
- }
-
-
- /*
- * Write a tree structure to the given IFF stream as a FORM HTXT.
- * Nested trees dealt with recursivly as embedded FORM HTXT's.
- */
- LONG
- WriteTree (iff, tree)
- struct IFFHandle *iff;
- struct HNode *tree;
- {
- register struct HNode *hn;
- register LONG error, size;
-
- if (!tree)
- return (0);
-
- /*
- * A node structure corresponds to a FORM HTXT chunk with the
- * internal parts of the tree as chunks within this chunk.
- */
- if (tree -> type == HN_NODE) {
- if (error = PushChunk
- (iff, ID_HTXT, ID_FORM, IFFSIZE_UNKNOWN))
- return (error);
-
- for (hn = tree -> val; hn; hn = hn -> next)
- if (error = WriteTree (iff, hn))
- return (error);
- /*
- * Leaf nodes correspond to CHRS chunks within their bounding
- * HTXT FORM.
- */
- } else {
- if (error = PushChunk (iff, 0L, ID_CHRS, IFFSIZE_UNKNOWN))
- return (error);
-
- size = strlen (tree -> val);
- if (WriteChunkRecords (iff, tree -> val, 1L, size) != size)
- return (IFFERR_WRITE);
- }
-
- return (PopChunk (iff));
- }
-
-
- /*
- * Reading uses a custom handler for the HTXT.FORM chunk. The handler
- * installs a handler for HTXT.CHRS chunks and provides a place for the
- * result of the parse to accumulate. The end result finishes in the
- * node at the root level of the structure.
- */
- LONG
- ReadTree (iff)
- struct IFFHandle *iff;
- {
- register struct LocalContextItem *lci;
- register struct HNode *tree, *hn;
- register struct vHNode *vhn;
- register struct ContextNode *top;
- long error;
- static struct Hook treehook = {
- { NULL },
- (ULONG (*)()) TreeHandler,
- NULL,
- NULL
- };
-
- /*
- * Install custom handler for HTXT.FORM chunks and
- * set up to stop at the end of same.
- */
- if (error = EntryHandler (iff, ID_HTXT, ID_FORM, IFFSLI_ROOT,
- &treehook, (APTR) iff))
- return (error);
-
- if (error = StopOnExit (iff, ID_HTXT, ID_FORM))
- return (error);
-
- /*
- * Parse that file and let the handlers do their work.
- * Also process end of context conditions for exiting
- * HTXT FORM's.
- */
- while (1) {
- /*
- * SCAN parse will return either EOF at the end of file
- * or EOC for the end of HTXT FORM context or error.
- * Since we'll "break" when exiting the last FORM, even
- * the EOF case can be considered an error.
- */
- error = ParseIFF (iff, IFFPARSE_STEP);
- if (!error) continue;
- if (error != IFFERR_EOC)
- return (error);
-
- top = CurrentChunk (iff);
- if (top -> cn_ID != ID_FORM || top -> cn_Type != ID_HTXT)
- continue;
-
- /*
- * We're about to exit a FORM HTXT, so look for the
- * tree data extracted for this FORM.
- */
- lci = FindLocalItem (iff, 0L, 0L, LCI_HNODE);
-
- if (!lci) {
- puts ("Error looking for result of FORM traversal.");
- tree = NULL;
- break;
- }
-
- /*
- * We're usurping this tree so the purge vector won't
- * try to deallocate it out from under us.
- */
- vhn = (struct vHNode *) LocalItemData (lci);
- tree = vhn -> val;
- vhn -> val = NULL;
-
- /*
- * Here's the kludgy part.
- *
- * We've got the tree for this FORM, so now we need to
- * propogate it backwards in the context stack and
- * attach it to the tree for the enclosing FORM.
- * So, take the LCI we just found and change the ID
- * field so a subsequent FindLocalItem() will find
- * the enclosing one. (Need a better way to do this!)
- */
- lci -> lci_ID = 1;
- lci = FindLocalItem (iff, 0L, 0L, LCI_HNODE);
-
- /*
- * If there is no enclosing FORM to be found, we're done.
- */
- if (!lci)
- break;
-
- /*
- * Take the tree found for this current FORM and make
- * make it a sub-tree of the enclosing one.
- */
- if (!(hn = AllocMem ((long) sizeof (*hn), 0L)))
- return (100);
-
- hn -> type = HN_NODE;
- hn -> next = NULL;
- hn -> val = tree;
- AddEnd ((struct vHNode *) LocalItemData (lci), hn);
-
- /*
- * Done processing end of FORM context -- keep parsing.
- */
- }
-
- /*
- * Do something interesting with the result.
- */
- puts ("result of read...");
- PrintTree (tree, 1);
- FreeTree (tree);
-
- return (0);
- }
-
-
- /*
- * Handler for the HTXT.FORM chunk. Install a local handler for
- * HTXT.CHRS chunks and provide a place in the current context for
- * result trees to attach themselves.
- */
- LONG __saveds __asm
- TreeHandler (
- register __a0 struct Hook *hook,
- register __a2 struct IFFHandle *iff,
- register __a1 LONG *cmd
- )
- {
- register struct LocalContextItem *lci;
- register struct vHNode *vhn;
- register LONG error;
- static struct Hook texthook = {
- { NULL },
- (ULONG (*)()) TextHandler,
- NULL,
- NULL
- };
- static struct Hook purgehook = {
- { NULL },
- (ULONG (*)()) PurgeVHNode,
- NULL,
- NULL
- };
-
- if (error = EntryHandler (iff, ID_HTXT, ID_CHRS, IFFSLI_TOP,
- &texthook, (APTR) iff))
- return (error);
-
- if (!(lci = AllocLocalItem (0L, 0L, LCI_HNODE,
- (long) sizeof (struct vHNode))))
- return (IFFERR_NOMEM);
-
- SetLocalItemPurge (lci, &purgehook);
-
- vhn = (struct vHNode *) LocalItemData (lci);
- vhn -> val = NULL;
-
- if (error = StoreLocalItem (iff, lci, IFFSLI_TOP)) {
- FreeLocalItem (lci);
- return (error);
- }
-
- return (0);
- }
-
-
- /*
- * Read HTXT.CHRS data into buffer and link into an HNode structure.
- * Attach this HNode to the locally available vHNode in this context.
- */
- LONG __saveds __asm
- TextHandler (
- register __a0 struct Hook *hook,
- register __a2 struct IFFHandle *iff,
- register __a1 LONG *cmd
- )
- {
- register struct vHNode *vhn;
- register struct HNode *hn;
-
- if (!(hn = AllocMem ((LONG) sizeof (*hn), 0L)))
- return (IFFERR_NOMEM);
-
- hn -> type = HN_LEAF;
- hn -> next = NULL;
- if (!(hn -> val = ReadTextChunk (iff))) {
- FreeTree (hn);
- return (-600);
- }
-
- /*
- * Locate the local vHNode and attach this HNode to it's list.
- */
- if (!(vhn = (struct vHNode *) LocalItemData (
- FindLocalItem (iff, 0L, 0L, LCI_HNODE))))
- {
- FreeTree (hn);
- return (-500);
- }
- AddEnd (vhn, hn);
-
- return (0);
- }
-
-
- /*
- * Read the contents of a CHRS chunk into a buffer and return pointer.
- */
- char *
- ReadTextChunk (iff)
- struct IFFHandle *iff;
- {
- register LONG siz;
- register char *t;
-
- t = &tbuf[bufpos];
- siz = CurrentChunk (iff) -> cn_Size;
- if (ReadChunkBytes (iff, (APTR) t, siz) != siz)
- return (NULL);
-
- bufpos += siz;
- tbuf[bufpos++] = 0;
-
- return (t);
- }
-
-
- /*
- * Attach HNode to the end of list attached to "vhn".
- * List will be reversed otherwise.
- */
- void
- AddEnd (vhn, hn)
- struct vHNode *vhn;
- struct HNode *hn;
- {
- register struct HNode *t;
-
- if (!vhn -> val) {
- vhn -> val = hn;
- hn -> next = NULL;
- } else {
- /*
- * Find end of list (next == NULL).
- */
- for (t = vhn -> val; t -> next; t = t -> next)
- ;
- t -> next = hn;
- hn -> next = NULL;
- }
- }
-
-
- /*
- * If everything goes right, we don't really need to use a special
- * purge vector for vHNodes since the tree will have been removed.
- * If something goes wrong and parsing is inturrupted, however,
- * CloseIFF() will try to purge all the local context items and
- * this item should be able to clean itself up if it's in an
- * intermediate state.
- */
- LONG __saveds __asm
- PurgeVHNode (
- register __a0 struct Hook *hook,
- register __a2 struct LocalContextItem *lci,
- register __a1 LONG *cmd
- )
- {
- register struct vHNode *vhn;
-
- vhn = (struct vHNode *) LocalItemData (lci);
- if (vhn -> val)
- FreeTree (vhn -> val);
- FreeLocalItem (lci);
-
- return (0);
- }
-
-
- /*
- * Recursive-descent parser for the HTXT tree structure.
- */
- LONG
- ReadTreeR (iff)
- struct IFFHandle *iff;
- {
- register LONG error;
- register struct HNode *tree;
-
- if (error = StopChunk (iff, ID_HTXT, ID_FORM))
- return (error);
-
- if (error = ParseIFF (iff, IFFPARSE_SCAN))
- return (error);
-
- tree = ReadTreeForm (iff);
- if (!tree)
- return (-427);
-
- /*
- * Something interesting ...
- */
- puts ("result of recursive-descent parse ...");
- PrintTree (tree, 1);
- FreeTree (tree);
- return (0);
- }
-
-
- /*
- * With the iff file positioned just inside a FORM TREE, parse
- * the contents and return as a single HNode.
- */
- struct HNode *
- ReadTreeForm (iff)
- struct IFFHandle *iff;
- {
- register struct HNode *hn, *sub;
- register struct ContextNode *top;
- register LONG error;
-
- if (!(hn = AllocMem ((LONG) sizeof (*hn), 0L)))
- return (NULL);
-
- hn -> type = HN_NODE;
- hn -> next = NULL;
- hn -> val = NULL;
-
- while (1) {
- error = ParseIFF (iff, IFFPARSE_STEP);
- if (error == IFFERR_EOC || error == IFFERR_EOF)
- return (hn);
- if (error)
- goto escape;
-
- top = CurrentChunk (iff);
- if (top->cn_Type != ID_HTXT)
- continue;
-
- switch (top -> cn_ID) {
- case ID_FORM:
- if (!(sub = ReadTreeForm (iff)))
- goto escape;
- AddEnd ((struct vHNode *) &hn->val, sub);
- break;
-
- case ID_CHRS:
- if (!(sub = AllocMem ((LONG) sizeof (*sub), 0L)))
- goto escape;
- sub -> type = HN_LEAF;
- sub -> next = NULL;
- if (!(sub -> val = ReadTextChunk (iff))) {
- FreeTree (sub);
- goto escape;
- }
- AddEnd ((struct vHNode *) &hn->val, sub);
-
- /*
- * Pop CHRS chunk.
- */
- if (ParseIFF (iff, IFFPARSE_STEP) != IFFERR_EOC)
- goto escape;
- break;
- }
- }
-
- escape:
- FreeTree (hn);
- return (NULL);
- }
-
-
- void
- PrintTree (tree, depth)
- struct HNode *tree;
- int depth;
- {
- int i;
-
- if (!tree)
- return;
-
- for (i = 0; i < depth; i++)
- printf (". ");
-
- if (tree -> type == HN_NODE) {
- printf ("node\n");
- PrintTree (tree -> val, depth + 1);
- } else {
- printf ("leaf: %s\n", tree -> val);
- }
- PrintTree (tree -> next, depth);
- }
-
-
- void
- FreeTree (tree)
- struct HNode *tree;
- {
- if (!tree)
- return;
-
- if (tree -> type == HN_NODE)
- FreeTree (tree -> val);
- FreeTree (tree -> next);
- FreeMem (tree, (LONG) sizeof (*tree));
- }
-
- /*
- * Disable Lattice's default ^C trap.
- */
- chkabort ()
- {
- return (0);
- }
-
- CXBRK ()
- {
- return (0);
- }
-